Here are some maps exploring our bird data. I have three sets of maps: Maps with all of the observations (All observations tab), maps only with localities where there are at least three individuals per species (>= 3 species tab), and maps that show the species density, rather than observation density (Species density tab). Let me know if y’all want me to map things differently too! Laura, this should be adaptable to exploring other data sets and we can sit down together if my code comments aren’t clear.

First I’m reading in the packages and setting my working directory where the data is, and reading in the data.

packages <- c("magrittr", "tidyverse", "sf", "leaflet", "maps", "ggmap", "viridis")
lapply(packages, require, character.only = TRUE)
setwd("/Users/connorfrench/Dropbox/Old_Mac/School_Stuff/CUNY/BigAss-bird-phylogeography")
#read in data
bird_data <- read.csv("sample_key_68_clean.csv")

Taking a look at the head and structure of the data set.

head(bird_data)
str(bird_data)
'data.frame':   18954 obs. of  21 variables:
 $ Sample.Name    : Factor w/ 18894 levels "1","1_Campylopterus_curvipennis_ord_0305",..: 6711 13902 13903 12820 12821 2579 7800 7801 2577 18692 ...
 $ treFile        : Factor w/ 183 levels "Adelomyia-melanogenys.tre",..: 129 104 104 129 129 118 64 64 118 180 ...
 $ Genus          : Factor w/ 197 levels "Adelomyia","Aegithalos",..: 143 113 113 143 143 135 75 75 135 196 ...
 $ Species        : Factor w/ 564 levels "abeillei","aedon",..: 163 492 492 266 266 100 560 560 100 211 ...
 $ ClemName       : Factor w/ 641 levels "Adelomyia melanogenys",..: 451 371 371 452 452 418 243 243 418 633 ...
 $ Subspecies     : Factor w/ 578 levels "","aenea","aestiva",..: 184 344 344 344 344 307 571 571 307 219 ...
 $ Split          : Factor w/ 272 levels "Adelomyia-melanogenys",..: 196 166 166 197 197 180 109 109 180 267 ...
 $ Lumped         : Factor w/ 183 levels "Adelomyia-melanogenys",..: 129 104 104 129 129 118 64 64 118 180 ...
 $ Ingroup        : Factor w/ 3 levels "drop","n","y": 3 3 3 3 3 3 3 3 3 3 ...
 $ Country        : Factor w/ 35 levels "","Antigua","Argentina",..: 33 7 7 3 3 3 3 3 3 7 ...
 $ State          : Factor w/ 422 levels ""," La Ceiba",..: 335 347 347 226 226 105 303 303 105 347 ...
 $ Locality       : Factor w/ 2736 levels ""," Ancon de Iturre, ~1 km NE of town",..: 2619 1654 1654 364 364 855 1549 1549 855 2128 ...
 $ Lat            : num  -31.1 -28.7 -28.7 -28.1 -28.1 ...
 $ Long           : num  -57.9 -49.8 -49.8 -55.6 -55.6 ...
 $ Notes          : Factor w/ 5 levels "hybrid","monticola",..: NA NA NA NA NA NA NA NA NA NA ...
 $ clem_group0.9  : int  1 1 1 1 1 2 3 3 1 2 ...
 $ clem_group0.8  : int  1 1 1 1 1 2 3 3 1 3 ...
 $ clem_group0.7  : int  1 1 1 1 1 2 3 3 1 3 ...
 $ lumped_group0.9: int  8 2 2 9 9 2 6 6 1 2 ...
 $ lumped_group0.8: int  8 2 2 9 9 2 6 6 1 3 ...
 $ lumped_group0.7: int  8 2 2 9 9 2 6 6 1 3 ...

I’m removing all of the irrelevant columns for mapping, I’m only keeping ingroup individuals, and I’m removing all localities that aren’t in South America.

#remove irrelevant columns, NAs, North American/European localities,and subset for ingroup individuals. orig # obs = 18954; filtered # obs = 2825
bird_data <- subset(bird_data, select = c("Country", "State", "Locality", "Genus", "Species", "Ingroup", "Lat", "Long")) %>%
  subset(Ingroup == "y") %>%
  subset(Lat < 12.5) %>%
  subset(!(Country %in% c("Mexico", "Cuba", "Bahamas", "Dominican Republic", "Nicaragua", "Costa Rica", "Panama"))) %>% 
  na.omit() %>%
  droplevels.data.frame()

Let’s take a look at our data after filtering. Of note: I forgot to drop the levels before looking at the data for our 9-12-18 meeting, and vastly overestimated the number of species we had. It’s actually 68. The original number of observations was 18954, and the filtered number of observations is 2825.

head(bird_data)
str(bird_data)
'data.frame':   2825 obs. of  8 variables:
 $ Country : Factor w/ 13 levels "Argentina","Bolivia",..: 12 3 3 1 1 1 1 1 1 3 ...
 $ State   : Factor w/ 156 levels "","AC","Acre",..: 124 127 127 81 81 40 113 113 40 127 ...
 $ Locality: Factor w/ 812 levels ""," Barcelos, left bank Rio Cuiuni",..: 775 457 457 168 168 269 433 433 269 601 ...
 $ Genus   : Factor w/ 52 levels "Anabacerthia",..: 38 32 32 38 38 36 17 17 36 52 ...
 $ Species : Factor w/ 68 levels "armillata","atronitens",..: 20 55 55 29 29 8 68 68 8 23 ...
 $ Ingroup : Factor w/ 1 level "y": 1 1 1 1 1 1 1 1 1 1 ...
 $ Lat     : num  -31.1 -28.7 -28.7 -28.1 -28.1 ...
 $ Long    : num  -57.9 -49.8 -49.8 -55.6 -55.6 ...
 - attr(*, "na.action")= 'omit' Named int  30 31 32 33 34 37 38 39 86 87 ...
  ..- attr(*, "names")= chr  "31" "32" "33" "34" ...

Now time for the map! This is of all of our South American localities colored according to country to find outlier/mislabeled points.

#convert locality data to a spatial object. The spatial object is basically a shape file that the mapping function can interpret. 
coord_points <- st_as_sf(bird_data, coords = c("Long", "Lat"), 
                         crs = 4326, agr = "constant")
#load a world map as the base map.
w_map <- map("world", plot = FALSE)
#make color palette
pal <- colorFactor(palette = "inferno", domain = NULL)
#create popup labels for points
popup_label <- paste(coord_points$Genus, coord_points$Species, "<br>",
                     coord_points$Country, "<br>",
                     coord_points$Locality, "<br>",
                     coord_points$geometry)
#plot in leafly
leaflet(data = w_map) %>% 
  addTiles() %>%
  addCircleMarkers(data = coord_points,
                  color = ~pal(Country),
                  radius = 5,
                  popup = popup_label)

Now I’m going to apply various filters to the data to look at sampling intensity. First I’m going to plot maps where localities with less than three observations are grey and three or more observations are red. This is irrespective of species, and is intended to provide a course idea of where we know there can’t be 3 or more observations for a species per locality.

Sampling Maps

All Observations

Here’s a 1 degree (~100 km x 100 km at equator) grid resolution.

#Acquire a base map that's compatible with ggmap (the maps you get from the map() function aren't compatible with ggmap). This is the best resolution I can get to visualize all of South America.
sa_map <- get_map(location = c(-67.9037, -23.0301), source = "google", zoom = 3, maptype = "satellite")
Map from URL : http://maps.googleapis.com/maps/api/staticmap?center=-23.0301,-67.9037&zoom=3&size=640x640&scale=2&maptype=satellite&language=en-EN&sensor=false
sa_all_binary_100 <- ggmap(sa_map) + 
  stat_bin2d(data = bird_data, aes(x = Long, y = Lat), binwidth = c(1, 1)) + 
  scale_fill_gradientn(lim = c(3,200), colors = "red") + 
  guides(fill = FALSE)
sa_all_binary_100

Here’s a 2 degree (~ 220 km x 220 km) grid resolution.

sa_all_binary_200 <- ggmap(sa_map) + 
  stat_bin2d(data = bird_data, aes(x = Long, y = Lat), binwidth = c(2, 2)) + 
  scale_fill_gradientn(lim = c(3,200), colors = "red") + 
  guides(fill = FALSE)
sa_all_binary_200

Here’s a 3 degree resolution.

sa_all_binary_300 <- ggmap(sa_map) + 
  stat_bin2d(data = bird_data, aes(x = Long, y = Lat), binwidth = c(3, 3)) + 
  scale_fill_gradientn(lim = c(3,200), colors = "red") + 
  guides(fill = FALSE)
sa_all_binary_300

>=3 per species

Here I’m subsetting the data for only those localities where there are more than 3 observations for a species and then plotting. This reduced our data set from 68 species to 38 species and 2825 observations to 1253 observations

##filtering for localities that have more than 3 observations for each species of bird
bird_data_3 <- bird_data %>%
  group_by(.dots = c("Species", "Long", "Lat")) %>% #this groups the species and coordinates so I can filter for species that have more than 2 duplicates of the Longitude and Latitude (i.e. more than 2 observations at each locality)
  filter(n() > 2)
#ungroup the data set to prevent wonky things from happening later
ungroup(bird_data_3)
##Plot
#convert locality data to a spatial object. The spatial object is basically a shape file that the mapping function can interpret. 
coord_points_3 <- st_as_sf(bird_data_3, coords = c("Long", "Lat"), 
                         crs = 4326, agr = "constant")
#create popup labels for points. This is so we can click on the points for info
popup_label_3 <- paste(coord_points_3$Genus, coord_points_3$Species, "<br>",
                     coord_points_3$Country, "<br>",
                     coord_points_3$Locality, "<br>",
                     coord_points_3$geometry)
#plot in leafly
leaflet(data = w_map) %>% 
  addTiles() %>%
  addCircleMarkers(data = coord_points_3,
                  color = ~pal(Country),
                  radius = 5,
                  popup = popup_label)

As a sanity check, I’m re-plotting the binary map at 1 degree (100 km) resolution with the new data set to make sure there are no localities that have less than three observations. Everything looks good!

sa_all_binary_3_100 <- ggmap(sa_map) + 
  stat_bin2d(data = bird_data_3, aes(x = Long, y = Lat), binwidth = c(1, 1)) + 
  scale_fill_gradientn(lim = c(3,200), colors = "red") + 
  guides(fill = FALSE)
sa_all_binary_3_100

Now that I’ve removed localities with less than 3 observations per species, let’s check out the observation density per locality at the 100 km, 200 km, and 300 km resolutions. I’m making two plots: One with the full range, and one with all localities with more than 20 observations greyed out so we can see the sampling structure at lower-density localities.

100 km resolution.

sa_all_heat_100 <- ggmap(sa_map) + 
  stat_bin2d(data = bird_data_3, aes(x = Long, y = Lat), binwidth = c(1, 1)) + 
  scale_fill_viridis()
sa_all_heat_100

sa_all_heat_100_20 <- ggmap(sa_map) + 
  stat_bin2d(data = bird_data_3, aes(x = Long, y = Lat), binwidth = c(1, 1)) + 
  scale_fill_viridis(limits = c(3, 20))
sa_all_heat_100_20

200 km resolution.

sa_all_heat_200 <- ggmap(sa_map) + 
  stat_bin2d(data = bird_data_3, aes(x = Long, y = Lat), binwidth = c(2, 2)) + 
  scale_fill_viridis()
sa_all_heat_200

sa_all_heat_200_20 <- ggmap(sa_map) + 
  stat_bin2d(data = bird_data_3, aes(x = Long, y = Lat), binwidth = c(2, 2)) + 
  scale_fill_viridis(limits = c(3, 20))
sa_all_heat_200_20

300 km resolution.

sa_all_heat_300 <- ggmap(sa_map) + 
  stat_bin2d(data = bird_data_3, aes(x = Long, y = Lat), binwidth = c(3, 3)) + 
  scale_fill_viridis()
sa_all_heat_300

sa_all_heat_300_20 <- ggmap(sa_map) + 
  stat_bin2d(data = bird_data_3, aes(x = Long, y = Lat), binwidth = c(3, 3)) + 
  scale_fill_viridis(limits = c(3, 20))
sa_all_heat_300_20

Species density

Now I’m going to look at species density per cell for the three resolutions! I’m reducing the data set to a single species observation per locality and making a choropleth map from the reduced data set. I’m making two maps per resolution: one with all species and one where cells with greater than 5 observations are greyed so we can differentiate among cells with lower numbers of species

100 km.

#Filtering the data to only include rows with unique Lat and Long coordinates
bird_data_unique <- bird_data_3 %>%
  group_by(.dots = c("Species", "Long", "Lat")) %>%
  distinct()
sa_species_heat_100 <- ggmap(sa_map) + 
  stat_bin2d(data = bird_data_unique, aes(x = Long, y = Lat), binwidth = c(1, 1))+
  scale_fill_viridis()
sa_species_heat_100

sa_species_heat_100_5 <- ggmap(sa_map) + 
  stat_bin2d(data = bird_data_unique, aes(x = Long, y = Lat), binwidth = c(1, 1))+
  scale_fill_viridis(limits = c(0,5))
sa_species_heat_100_5

200 km.

sa_species_heat_200 <- ggmap(sa_map) + 
  stat_bin2d(data = bird_data_unique, aes(x = Long, y = Lat), binwidth = c(2, 2))+
  scale_fill_viridis()
sa_species_heat_200

sa_species_heat_200_5 <- ggmap(sa_map) + 
  stat_bin2d(data = bird_data_unique, aes(x = Long, y = Lat), binwidth = c(2, 2))+
  scale_fill_viridis(limits = c(0,5))
sa_species_heat_200_5

300 km.

sa_species_heat_300 <- ggmap(sa_map) + 
  stat_bin2d(data = bird_data_unique, aes(x = Long, y = Lat), binwidth = c(3, 3))+
  scale_fill_viridis()
sa_species_heat_300

sa_species_heat_300_5 <- ggmap(sa_map) + 
  stat_bin2d(data = bird_data_unique, aes(x = Long, y = Lat), binwidth = c(3, 3))+
  scale_fill_viridis(limits = c(0,5))
sa_species_heat_300_5

LS0tCnRpdGxlOiAiQmlnQXNzIGJpcmQgcGh5bG9nZW9ncmFwaHkgZGF0YSBleHBsb3JhdGlvbiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpIZXJlIGFyZSBzb21lIG1hcHMgZXhwbG9yaW5nIG91ciBiaXJkIGRhdGEuIEkgaGF2ZSB0aHJlZSBzZXRzIG9mIG1hcHM6IE1hcHMgd2l0aCBhbGwgb2YgdGhlIG9ic2VydmF0aW9ucyAoQWxsIG9ic2VydmF0aW9ucyB0YWIpLCBtYXBzIG9ubHkgd2l0aCBsb2NhbGl0aWVzIHdoZXJlIHRoZXJlIGFyZSBhdCBsZWFzdCB0aHJlZSBpbmRpdmlkdWFscyBwZXIgc3BlY2llcyAoPj0gMyBzcGVjaWVzIHRhYiksIGFuZCBtYXBzIHRoYXQgc2hvdyB0aGUgc3BlY2llcyBkZW5zaXR5LCByYXRoZXIgdGhhbiBvYnNlcnZhdGlvbiBkZW5zaXR5IChTcGVjaWVzIGRlbnNpdHkgdGFiKS4gTGV0IG1lIGtub3cgaWYgeSdhbGwgd2FudCBtZSB0byBtYXAgdGhpbmdzIGRpZmZlcmVudGx5IHRvbyEgTGF1cmEsIHRoaXMgc2hvdWxkIGJlIGFkYXB0YWJsZSB0byBleHBsb3Jpbmcgb3RoZXIgZGF0YSBzZXRzIGFuZCB3ZSBjYW4gc2l0IGRvd24gdG9nZXRoZXIgaWYgbXkgY29kZSBjb21tZW50cyBhcmVuJ3QgY2xlYXIuCgpGaXJzdCBJJ20gcmVhZGluZyBpbiB0aGUgcGFja2FnZXMgYW5kIHNldHRpbmcgbXkgd29ya2luZyBkaXJlY3Rvcnkgd2hlcmUgdGhlIGRhdGEgaXMsIGFuZCByZWFkaW5nIGluIHRoZSBkYXRhLgpgYGB7ciwgcmVzdWx0cz0naGlkZSd9CnBhY2thZ2VzIDwtIGMoIm1hZ3JpdHRyIiwgInRpZHl2ZXJzZSIsICJzZiIsICJsZWFmbGV0IiwgIm1hcHMiLCAiZ2dtYXAiLCAidmlyaWRpcyIpCmxhcHBseShwYWNrYWdlcywgcmVxdWlyZSwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQoKc2V0d2QoIi9Vc2Vycy9jb25ub3JmcmVuY2gvRHJvcGJveC9PbGRfTWFjL1NjaG9vbF9TdHVmZi9DVU5ZL0JpZ0Fzcy1iaXJkLXBoeWxvZ2VvZ3JhcGh5IikKCiNyZWFkIGluIGRhdGEKYmlyZF9kYXRhIDwtIHJlYWQuY3N2KCJzYW1wbGVfa2V5XzY4X2NsZWFuLmNzdiIpCmBgYAoKVGFraW5nIGEgbG9vayBhdCB0aGUgaGVhZCBhbmQgc3RydWN0dXJlIG9mIHRoZSBkYXRhIHNldC4KYGBge3J9CmhlYWQoYmlyZF9kYXRhKQpzdHIoYmlyZF9kYXRhKQpgYGAKCgoKSSdtIHJlbW92aW5nIGFsbCBvZiB0aGUgaXJyZWxldmFudCBjb2x1bW5zIGZvciBtYXBwaW5nLCBJJ20gb25seSBrZWVwaW5nIGluZ3JvdXAgaW5kaXZpZHVhbHMsIGFuZCBJJ20gcmVtb3ZpbmcgYWxsIGxvY2FsaXRpZXMgdGhhdCBhcmVuJ3QgaW4gU291dGggQW1lcmljYS4KCmBgYHtyfQojcmVtb3ZlIGlycmVsZXZhbnQgY29sdW1ucywgTkFzLCBOb3J0aCBBbWVyaWNhbi9FdXJvcGVhbiBsb2NhbGl0aWVzLGFuZCBzdWJzZXQgZm9yIGluZ3JvdXAgaW5kaXZpZHVhbHMuIG9yaWcgIyBvYnMgPSAxODk1NDsgZmlsdGVyZWQgIyBvYnMgPSAyODI1CmJpcmRfZGF0YSA8LSBzdWJzZXQoYmlyZF9kYXRhLCBzZWxlY3QgPSBjKCJDb3VudHJ5IiwgIlN0YXRlIiwgIkxvY2FsaXR5IiwgIkdlbnVzIiwgIlNwZWNpZXMiLCAiSW5ncm91cCIsICJMYXQiLCAiTG9uZyIpKSAlPiUKICBzdWJzZXQoSW5ncm91cCA9PSAieSIpICU+JQogIHN1YnNldChMYXQgPCAxMi41KSAlPiUKICBzdWJzZXQoIShDb3VudHJ5ICVpbiUgYygiTWV4aWNvIiwgIkN1YmEiLCAiQmFoYW1hcyIsICJEb21pbmljYW4gUmVwdWJsaWMiLCAiTmljYXJhZ3VhIiwgIkNvc3RhIFJpY2EiLCAiUGFuYW1hIikpKSAlPiUgCiAgbmEub21pdCgpICU+JQogIGRyb3BsZXZlbHMuZGF0YS5mcmFtZSgpCmBgYAoKTGV0J3MgdGFrZSBhIGxvb2sgYXQgb3VyIGRhdGEgYWZ0ZXIgZmlsdGVyaW5nLiBPZiBub3RlOiBJIGZvcmdvdCB0byBkcm9wIHRoZSBsZXZlbHMgYmVmb3JlIGxvb2tpbmcgYXQgdGhlIGRhdGEgZm9yIG91ciA5LTEyLTE4IG1lZXRpbmcsIGFuZCB2YXN0bHkgb3ZlcmVzdGltYXRlZCB0aGUgbnVtYmVyIG9mIHNwZWNpZXMgd2UgaGFkLiBJdCdzIGFjdHVhbGx5IDY4LiBUaGUgb3JpZ2luYWwgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyB3YXMgMTg5NTQsIGFuZCB0aGUgZmlsdGVyZWQgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpcyAyODI1LgoKYGBge3J9CmhlYWQoYmlyZF9kYXRhKQpzdHIoYmlyZF9kYXRhKQpgYGAKCiAgCk5vdyB0aW1lIGZvciB0aGUgbWFwISBUaGlzIGlzIG9mIGFsbCBvZiBvdXIgU291dGggQW1lcmljYW4gbG9jYWxpdGllcyBjb2xvcmVkIGFjY29yZGluZyB0byBjb3VudHJ5IHRvIGZpbmQgb3V0bGllci9taXNsYWJlbGVkIHBvaW50cy4KCmBgYHtyfQojY29udmVydCBsb2NhbGl0eSBkYXRhIHRvIGEgc3BhdGlhbCBvYmplY3QuIFRoZSBzcGF0aWFsIG9iamVjdCBpcyBiYXNpY2FsbHkgYSBzaGFwZSBmaWxlIHRoYXQgdGhlIG1hcHBpbmcgZnVuY3Rpb24gY2FuIGludGVycHJldC4gCmNvb3JkX3BvaW50cyA8LSBzdF9hc19zZihiaXJkX2RhdGEsIGNvb3JkcyA9IGMoIkxvbmciLCAiTGF0IiksIAogICAgICAgICAgICAgICAgICAgICAgICAgY3JzID0gNDMyNiwgYWdyID0gImNvbnN0YW50IikKCiNsb2FkIGEgd29ybGQgbWFwIGFzIHRoZSBiYXNlIG1hcC4Kd19tYXAgPC0gbWFwKCJ3b3JsZCIsIHBsb3QgPSBGQUxTRSkKCiNtYWtlIGNvbG9yIHBhbGV0dGUKcGFsIDwtIGNvbG9yRmFjdG9yKHBhbGV0dGUgPSAiaW5mZXJubyIsIGRvbWFpbiA9IE5VTEwpCgojY3JlYXRlIHBvcHVwIGxhYmVscyBmb3IgcG9pbnRzCnBvcHVwX2xhYmVsIDwtIHBhc3RlKGNvb3JkX3BvaW50cyRHZW51cywgY29vcmRfcG9pbnRzJFNwZWNpZXMsICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgY29vcmRfcG9pbnRzJENvdW50cnksICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgY29vcmRfcG9pbnRzJExvY2FsaXR5LCAiPGJyPiIsCiAgICAgICAgICAgICAgICAgICAgIGNvb3JkX3BvaW50cyRnZW9tZXRyeSkKCiNwbG90IGluIGxlYWZseQpsZWFmbGV0KGRhdGEgPSB3X21hcCkgJT4lIAogIGFkZFRpbGVzKCkgJT4lCiAgYWRkQ2lyY2xlTWFya2VycyhkYXRhID0gY29vcmRfcG9pbnRzLAogICAgICAgICAgICAgICAgICBjb2xvciA9IH5wYWwoQ291bnRyeSksCiAgICAgICAgICAgICAgICAgIHJhZGl1cyA9IDUsCiAgICAgICAgICAgICAgICAgIHBvcHVwID0gcG9wdXBfbGFiZWwpCmBgYAoKCk5vdyBJJ20gZ29pbmcgdG8gYXBwbHkgdmFyaW91cyBmaWx0ZXJzIHRvIHRoZSBkYXRhIHRvIGxvb2sgYXQgc2FtcGxpbmcgaW50ZW5zaXR5LiBGaXJzdCBJJ20gZ29pbmcgdG8gcGxvdCBtYXBzIHdoZXJlIGxvY2FsaXRpZXMgd2l0aCBsZXNzIHRoYW4gdGhyZWUgb2JzZXJ2YXRpb25zIGFyZSBncmV5IGFuZCB0aHJlZSBvciBtb3JlIG9ic2VydmF0aW9ucyBhcmUgcmVkLiBUaGlzIGlzIGlycmVzcGVjdGl2ZSBvZiBzcGVjaWVzLCBhbmQgaXMgaW50ZW5kZWQgdG8gcHJvdmlkZSBhIGNvdXJzZSBpZGVhIG9mIHdoZXJlIHdlIGtub3cgdGhlcmUgY2FuJ3QgYmUgMyBvciBtb3JlIG9ic2VydmF0aW9ucyBmb3IgYSBzcGVjaWVzIHBlciBsb2NhbGl0eS4KCiMjU2FtcGxpbmcgTWFwcyB7LnRhYnNldH0KCiMjI0FsbCBPYnNlcnZhdGlvbnMKSGVyZSdzIGEgMSBkZWdyZWUgKH4xMDAga20geCAxMDAga20gYXQgZXF1YXRvcikgZ3JpZCByZXNvbHV0aW9uLiAKYGBge3J9CiNBY3F1aXJlIGEgYmFzZSBtYXAgdGhhdCdzIGNvbXBhdGlibGUgd2l0aCBnZ21hcCAodGhlIG1hcHMgeW91IGdldCBmcm9tIHRoZSBtYXAoKSBmdW5jdGlvbiBhcmVuJ3QgY29tcGF0aWJsZSB3aXRoIGdnbWFwKS4gVGhpcyBpcyB0aGUgYmVzdCByZXNvbHV0aW9uIEkgY2FuIGdldCB0byB2aXN1YWxpemUgYWxsIG9mIFNvdXRoIEFtZXJpY2EuCnNhX21hcCA8LSBnZXRfbWFwKGxvY2F0aW9uID0gYygtNjcuOTAzNywgLTIzLjAzMDEpLCBzb3VyY2UgPSAiZ29vZ2xlIiwgem9vbSA9IDMsIG1hcHR5cGUgPSAic2F0ZWxsaXRlIikKCnNhX2FsbF9iaW5hcnlfMTAwIDwtIGdnbWFwKHNhX21hcCkgKyAKICBzdGF0X2JpbjJkKGRhdGEgPSBiaXJkX2RhdGEsIGFlcyh4ID0gTG9uZywgeSA9IExhdCksIGJpbndpZHRoID0gYygxLCAxKSkgKyAKICBzY2FsZV9maWxsX2dyYWRpZW50bihsaW0gPSBjKDMsMjAwKSwgY29sb3JzID0gInJlZCIpICsgCiAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkKCnNhX2FsbF9iaW5hcnlfMTAwCgpgYGAKCkhlcmUncyBhIDIgZGVncmVlICh+IDIyMCBrbSB4IDIyMCBrbSkgZ3JpZCByZXNvbHV0aW9uLgpgYGB7cn0Kc2FfYWxsX2JpbmFyeV8yMDAgPC0gZ2dtYXAoc2FfbWFwKSArIAogIHN0YXRfYmluMmQoZGF0YSA9IGJpcmRfZGF0YSwgYWVzKHggPSBMb25nLCB5ID0gTGF0KSwgYmlud2lkdGggPSBjKDIsIDIpKSArIAogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGxpbSA9IGMoMywyMDApLCBjb2xvcnMgPSAicmVkIikgKyAKICBndWlkZXMoZmlsbCA9IEZBTFNFKQoKc2FfYWxsX2JpbmFyeV8yMDAKYGBgCgoKSGVyZSdzIGEgMyBkZWdyZWUgcmVzb2x1dGlvbi4KYGBge3J9CnNhX2FsbF9iaW5hcnlfMzAwIDwtIGdnbWFwKHNhX21hcCkgKyAKICBzdGF0X2JpbjJkKGRhdGEgPSBiaXJkX2RhdGEsIGFlcyh4ID0gTG9uZywgeSA9IExhdCksIGJpbndpZHRoID0gYygzLCAzKSkgKyAKICBzY2FsZV9maWxsX2dyYWRpZW50bihsaW0gPSBjKDMsMjAwKSwgY29sb3JzID0gInJlZCIpICsgCiAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkKCnNhX2FsbF9iaW5hcnlfMzAwCmBgYAoKCiMjIz49MyBwZXIgc3BlY2llcwpIZXJlIEknbSBzdWJzZXR0aW5nIHRoZSBkYXRhIGZvciBvbmx5IHRob3NlIGxvY2FsaXRpZXMgd2hlcmUgdGhlcmUgYXJlIG1vcmUgdGhhbiAzIG9ic2VydmF0aW9ucyBmb3IgYSBzcGVjaWVzIGFuZCB0aGVuIHBsb3R0aW5nLiBUaGlzIHJlZHVjZWQgb3VyIGRhdGEgc2V0IGZyb20gNjggc3BlY2llcyB0byAzOCBzcGVjaWVzIGFuZCAyODI1IG9ic2VydmF0aW9ucyB0byAxMjUzIG9ic2VydmF0aW9ucwpgYGB7cn0KIyNmaWx0ZXJpbmcgZm9yIGxvY2FsaXRpZXMgdGhhdCBoYXZlIG1vcmUgdGhhbiAzIG9ic2VydmF0aW9ucyBmb3IgZWFjaCBzcGVjaWVzIG9mIGJpcmQKYmlyZF9kYXRhXzMgPC0gYmlyZF9kYXRhICU+JQogIGdyb3VwX2J5KC5kb3RzID0gYygiU3BlY2llcyIsICJMb25nIiwgIkxhdCIpKSAlPiUgI3RoaXMgZ3JvdXBzIHRoZSBzcGVjaWVzIGFuZCBjb29yZGluYXRlcyBzbyBJIGNhbiBmaWx0ZXIgZm9yIHNwZWNpZXMgdGhhdCBoYXZlIG1vcmUgdGhhbiAyIGR1cGxpY2F0ZXMgb2YgdGhlIExvbmdpdHVkZSBhbmQgTGF0aXR1ZGUgKGkuZS4gbW9yZSB0aGFuIDIgb2JzZXJ2YXRpb25zIGF0IGVhY2ggbG9jYWxpdHkpCiAgZmlsdGVyKG4oKSA+IDIpCgojdW5ncm91cCB0aGUgZGF0YSBzZXQgdG8gcHJldmVudCB3b25reSB0aGluZ3MgZnJvbSBoYXBwZW5pbmcgbGF0ZXIKdW5ncm91cChiaXJkX2RhdGFfMykKCgojI1Bsb3QKI2NvbnZlcnQgbG9jYWxpdHkgZGF0YSB0byBhIHNwYXRpYWwgb2JqZWN0LiBUaGUgc3BhdGlhbCBvYmplY3QgaXMgYmFzaWNhbGx5IGEgc2hhcGUgZmlsZSB0aGF0IHRoZSBtYXBwaW5nIGZ1bmN0aW9uIGNhbiBpbnRlcnByZXQuIApjb29yZF9wb2ludHNfMyA8LSBzdF9hc19zZihiaXJkX2RhdGFfMywgY29vcmRzID0gYygiTG9uZyIsICJMYXQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBjcnMgPSA0MzI2LCBhZ3IgPSAiY29uc3RhbnQiKQoKI2NyZWF0ZSBwb3B1cCBsYWJlbHMgZm9yIHBvaW50cy4gVGhpcyBpcyBzbyB3ZSBjYW4gY2xpY2sgb24gdGhlIHBvaW50cyBmb3IgaW5mbwpwb3B1cF9sYWJlbF8zIDwtIHBhc3RlKGNvb3JkX3BvaW50c18zJEdlbnVzLCBjb29yZF9wb2ludHNfMyRTcGVjaWVzLCAiPGJyPiIsCiAgICAgICAgICAgICAgICAgICAgIGNvb3JkX3BvaW50c18zJENvdW50cnksICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgY29vcmRfcG9pbnRzXzMkTG9jYWxpdHksICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgY29vcmRfcG9pbnRzXzMkZ2VvbWV0cnkpCgojcGxvdCBpbiBsZWFmbHkKbGVhZmxldChkYXRhID0gd19tYXApICU+JSAKICBhZGRUaWxlcygpICU+JQogIGFkZENpcmNsZU1hcmtlcnMoZGF0YSA9IGNvb3JkX3BvaW50c18zLAogICAgICAgICAgICAgICAgICBjb2xvciA9IH5wYWwoQ291bnRyeSksCiAgICAgICAgICAgICAgICAgIHJhZGl1cyA9IDUsCiAgICAgICAgICAgICAgICAgIHBvcHVwID0gcG9wdXBfbGFiZWwpCgpgYGAKCgoKCkFzIGEgc2FuaXR5IGNoZWNrLCBJJ20gcmUtcGxvdHRpbmcgdGhlIGJpbmFyeSBtYXAgYXQgMSBkZWdyZWUgKDEwMCBrbSkgcmVzb2x1dGlvbiB3aXRoIHRoZSBuZXcgZGF0YSBzZXQgdG8gbWFrZSBzdXJlIHRoZXJlIGFyZSBubyBsb2NhbGl0aWVzIHRoYXQgaGF2ZSBsZXNzIHRoYW4gdGhyZWUgb2JzZXJ2YXRpb25zLiBFdmVyeXRoaW5nIGxvb2tzIGdvb2QhCgpgYGB7cn0Kc2FfYWxsX2JpbmFyeV8zXzEwMCA8LSBnZ21hcChzYV9tYXApICsgCiAgc3RhdF9iaW4yZChkYXRhID0gYmlyZF9kYXRhXzMsIGFlcyh4ID0gTG9uZywgeSA9IExhdCksIGJpbndpZHRoID0gYygxLCAxKSkgKyAKICBzY2FsZV9maWxsX2dyYWRpZW50bihsaW0gPSBjKDMsMjAwKSwgY29sb3JzID0gInJlZCIpICsgCiAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkKCnNhX2FsbF9iaW5hcnlfM18xMDAKYGBgCgoKCk5vdyB0aGF0IEkndmUgcmVtb3ZlZCBsb2NhbGl0aWVzIHdpdGggbGVzcyB0aGFuIDMgb2JzZXJ2YXRpb25zIHBlciBzcGVjaWVzLCBsZXQncyBjaGVjayBvdXQgdGhlIG9ic2VydmF0aW9uIGRlbnNpdHkgcGVyIGxvY2FsaXR5IGF0IHRoZSAxMDAga20sIDIwMCBrbSwgYW5kIDMwMCBrbSByZXNvbHV0aW9ucy4gSSdtIG1ha2luZyB0d28gcGxvdHM6IE9uZSB3aXRoIHRoZSBmdWxsIHJhbmdlLCBhbmQgb25lIHdpdGggYWxsIGxvY2FsaXRpZXMgd2l0aCBtb3JlIHRoYW4gMjAgb2JzZXJ2YXRpb25zIGdyZXllZCBvdXQgc28gd2UgY2FuIHNlZSB0aGUgc2FtcGxpbmcgc3RydWN0dXJlIGF0IGxvd2VyLWRlbnNpdHkgbG9jYWxpdGllcy4KCjEwMCBrbSByZXNvbHV0aW9uLgpgYGB7cn0Kc2FfYWxsX2hlYXRfMTAwIDwtIGdnbWFwKHNhX21hcCkgKyAKICBzdGF0X2JpbjJkKGRhdGEgPSBiaXJkX2RhdGFfMywgYWVzKHggPSBMb25nLCB5ID0gTGF0KSwgYmlud2lkdGggPSBjKDEsIDEpKSArIAogIHNjYWxlX2ZpbGxfdmlyaWRpcygpCgpzYV9hbGxfaGVhdF8xMDAKCnNhX2FsbF9oZWF0XzEwMF8yMCA8LSBnZ21hcChzYV9tYXApICsgCiAgc3RhdF9iaW4yZChkYXRhID0gYmlyZF9kYXRhXzMsIGFlcyh4ID0gTG9uZywgeSA9IExhdCksIGJpbndpZHRoID0gYygxLCAxKSkgKyAKICBzY2FsZV9maWxsX3ZpcmlkaXMobGltaXRzID0gYygzLCAyMCkpCgpzYV9hbGxfaGVhdF8xMDBfMjAKYGBgCgoKMjAwIGttIHJlc29sdXRpb24uCgpgYGB7cn0Kc2FfYWxsX2hlYXRfMjAwIDwtIGdnbWFwKHNhX21hcCkgKyAKICBzdGF0X2JpbjJkKGRhdGEgPSBiaXJkX2RhdGFfMywgYWVzKHggPSBMb25nLCB5ID0gTGF0KSwgYmlud2lkdGggPSBjKDIsIDIpKSArIAogIHNjYWxlX2ZpbGxfdmlyaWRpcygpCgpzYV9hbGxfaGVhdF8yMDAKCnNhX2FsbF9oZWF0XzIwMF8yMCA8LSBnZ21hcChzYV9tYXApICsgCiAgc3RhdF9iaW4yZChkYXRhID0gYmlyZF9kYXRhXzMsIGFlcyh4ID0gTG9uZywgeSA9IExhdCksIGJpbndpZHRoID0gYygyLCAyKSkgKyAKICBzY2FsZV9maWxsX3ZpcmlkaXMobGltaXRzID0gYygzLCAyMCkpCgpzYV9hbGxfaGVhdF8yMDBfMjAKYGBgCgoKMzAwIGttIHJlc29sdXRpb24uCgpgYGB7cn0Kc2FfYWxsX2hlYXRfMzAwIDwtIGdnbWFwKHNhX21hcCkgKyAKICBzdGF0X2JpbjJkKGRhdGEgPSBiaXJkX2RhdGFfMywgYWVzKHggPSBMb25nLCB5ID0gTGF0KSwgYmlud2lkdGggPSBjKDMsIDMpKSArIAogIHNjYWxlX2ZpbGxfdmlyaWRpcygpCgpzYV9hbGxfaGVhdF8zMDAKCnNhX2FsbF9oZWF0XzMwMF8yMCA8LSBnZ21hcChzYV9tYXApICsgCiAgc3RhdF9iaW4yZChkYXRhID0gYmlyZF9kYXRhXzMsIGFlcyh4ID0gTG9uZywgeSA9IExhdCksIGJpbndpZHRoID0gYygzLCAzKSkgKyAKICBzY2FsZV9maWxsX3ZpcmlkaXMobGltaXRzID0gYygzLCAyMCkpCgpzYV9hbGxfaGVhdF8zMDBfMjAKYGBgCgojIyNTcGVjaWVzIGRlbnNpdHkKTm93IEknbSBnb2luZyB0byBsb29rIGF0IHNwZWNpZXMgZGVuc2l0eSBwZXIgY2VsbCBmb3IgdGhlIHRocmVlIHJlc29sdXRpb25zISBJJ20gcmVkdWNpbmcgdGhlIGRhdGEgc2V0IHRvIGEgc2luZ2xlIHNwZWNpZXMgb2JzZXJ2YXRpb24gcGVyIGxvY2FsaXR5IGFuZCBtYWtpbmcgYSBjaG9yb3BsZXRoIG1hcCBmcm9tIHRoZSByZWR1Y2VkIGRhdGEgc2V0LiBJJ20gbWFraW5nIHR3byBtYXBzIHBlciByZXNvbHV0aW9uOiBvbmUgd2l0aCBhbGwgc3BlY2llcyBhbmQgb25lIHdoZXJlIGNlbGxzIHdpdGggZ3JlYXRlciB0aGFuIDUgb2JzZXJ2YXRpb25zIGFyZSBncmV5ZWQgc28gd2UgY2FuIGRpZmZlcmVudGlhdGUgYW1vbmcgY2VsbHMgd2l0aCBsb3dlciBudW1iZXJzIG9mIHNwZWNpZXMKCgoxMDAga20uIApgYGB7cn0KI0ZpbHRlcmluZyB0aGUgZGF0YSB0byBvbmx5IGluY2x1ZGUgcm93cyB3aXRoIHVuaXF1ZSBMYXQgYW5kIExvbmcgY29vcmRpbmF0ZXMKYmlyZF9kYXRhX3VuaXF1ZSA8LSBiaXJkX2RhdGFfMyAlPiUKICBncm91cF9ieSguZG90cyA9IGMoIlNwZWNpZXMiLCAiTG9uZyIsICJMYXQiKSkgJT4lCiAgZGlzdGluY3QoKQoKCnNhX3NwZWNpZXNfaGVhdF8xMDAgPC0gZ2dtYXAoc2FfbWFwKSArIAogIHN0YXRfYmluMmQoZGF0YSA9IGJpcmRfZGF0YV91bmlxdWUsIGFlcyh4ID0gTG9uZywgeSA9IExhdCksIGJpbndpZHRoID0gYygxLCAxKSkrCiAgc2NhbGVfZmlsbF92aXJpZGlzKCkKCnNhX3NwZWNpZXNfaGVhdF8xMDAKCnNhX3NwZWNpZXNfaGVhdF8xMDBfNSA8LSBnZ21hcChzYV9tYXApICsgCiAgc3RhdF9iaW4yZChkYXRhID0gYmlyZF9kYXRhX3VuaXF1ZSwgYWVzKHggPSBMb25nLCB5ID0gTGF0KSwgYmlud2lkdGggPSBjKDEsIDEpKSsKICBzY2FsZV9maWxsX3ZpcmlkaXMobGltaXRzID0gYygwLDUpKQoKc2Ffc3BlY2llc19oZWF0XzEwMF81CgoKYGBgCgoyMDAga20uCmBgYHtyfQpzYV9zcGVjaWVzX2hlYXRfMjAwIDwtIGdnbWFwKHNhX21hcCkgKyAKICBzdGF0X2JpbjJkKGRhdGEgPSBiaXJkX2RhdGFfdW5pcXVlLCBhZXMoeCA9IExvbmcsIHkgPSBMYXQpLCBiaW53aWR0aCA9IGMoMiwgMikpKwogIHNjYWxlX2ZpbGxfdmlyaWRpcygpCgpzYV9zcGVjaWVzX2hlYXRfMjAwCgpzYV9zcGVjaWVzX2hlYXRfMjAwXzUgPC0gZ2dtYXAoc2FfbWFwKSArIAogIHN0YXRfYmluMmQoZGF0YSA9IGJpcmRfZGF0YV91bmlxdWUsIGFlcyh4ID0gTG9uZywgeSA9IExhdCksIGJpbndpZHRoID0gYygyLCAyKSkrCiAgc2NhbGVfZmlsbF92aXJpZGlzKGxpbWl0cyA9IGMoMCw1KSkKCnNhX3NwZWNpZXNfaGVhdF8yMDBfNQoKYGBgCgoKMzAwIGttLgpgYGB7cn0Kc2Ffc3BlY2llc19oZWF0XzMwMCA8LSBnZ21hcChzYV9tYXApICsgCiAgc3RhdF9iaW4yZChkYXRhID0gYmlyZF9kYXRhX3VuaXF1ZSwgYWVzKHggPSBMb25nLCB5ID0gTGF0KSwgYmlud2lkdGggPSBjKDMsIDMpKSsKICBzY2FsZV9maWxsX3ZpcmlkaXMoKQoKc2Ffc3BlY2llc19oZWF0XzMwMAoKc2Ffc3BlY2llc19oZWF0XzMwMF81IDwtIGdnbWFwKHNhX21hcCkgKyAKICBzdGF0X2JpbjJkKGRhdGEgPSBiaXJkX2RhdGFfdW5pcXVlLCBhZXMoeCA9IExvbmcsIHkgPSBMYXQpLCBiaW53aWR0aCA9IGMoMywgMykpKwogIHNjYWxlX2ZpbGxfdmlyaWRpcyhsaW1pdHMgPSBjKDAsNSkpCgpzYV9zcGVjaWVzX2hlYXRfMzAwXzUKCmBgYAoKCgoKCgoKCgo=